<script setup lang="ts">
import { ref, reactive, toRefs, onMounted } from 'vue'
import G6 from '@antv/g6'
import insertCss from 'insert-css'

const containerRef = ref(null)
const curNodeData = ref(null)
const graphInstance = ref(null)

const COLLAPSE_ICON = function COLLAPSE_ICON(x, y, r) {
  return [
    ['M', x - r, y - r],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x + 2 - r, y - r],
    ['L', x + r - 2, y - r],
  ]
}
const EXPAND_ICON = function EXPAND_ICON(x, y, r) {
  return [
    ['M', x - r, y - r],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x + 2 - r, y - r],
    ['L', x + r - 2, y - r],
    ['M', x, y - 2 * r + 2],
    ['L', x, y - 2],
  ]
}

const data = ref({
  id: 'root',
  label: '发起人',
  nodeType: 'publisher',
  children: [
    {
      id: 'c1',
      label: '条件节点1',
      nodeType: 'condition',
      children: [
        {
          id: 'c1-1',
          label: '审批人A',
          nodeType: 'approver',
          children: [
            {
              id: 'c1-1-1',
              label: '审批人B',
              nodeType: 'approver',
            },
          ],
        },
      ],
    },
  ],
})
const initcontainerRef = () => {
  G6.Util.traverseTree(data.value, (d) => {
    d.label = d.label + d.valueName || ''
    return true
  })

  G6.registerNode(
    'icon-node',
    {
      options: {
        size: [60, 20],
        stroke: '#91d5ff',
        fill: '#91d5ff',
      },
      draw(cfg, group) {
        const styles = this.getShapeStyle(cfg)
        const { labelCfg = {} } = cfg

        const w = styles.width
        const h = styles.height

        const keyShape = group.addShape('rect', {
          attrs: {
            ...styles,
            x: -w / 2,
            y: -h / 2,
          },
        })

        /**
         * leftIcon 格式如下：
         *  {
         *    style: ShapeStyle;
         *    img: ''
         *  }
         */
        console.log('cfg.leftIcon', cfg.leftIcon)
        if (cfg.leftIcon) {
          const { style, img } = cfg.leftIcon
          group.addShape('rect', {
            attrs: {
              x: 1 - w / 2,
              y: 1 - h / 2,
              width: 38,
              height: styles.height - 2,
              fill: '#8c8c8c',
              ...style,
            },
          })

          group.addShape('image', {
            attrs: {
              x: 8 - w / 2,
              y: 8 - h / 2,
              width: 24,
              height: 24,
              img: img || 'https://g.alicdn.com/cm-design/arms-trace/1.0.155/styles/armsTrace/images/TAIR.png',
            },
            // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
            name: 'image-shape',
          })
        }

        // 如果不需要动态增加或删除元素，则不需要 add 这两个 marker
        group.addShape('marker', {
          attrs: {
            x: 40 - w / 2,
            y: 52 - h / 2,
            r: 6,
            stroke: '#73d13d',
            cursor: 'pointer',
            symbol: EXPAND_ICON,
          },
          // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
          name: 'add-item',
        })

        group.addShape('marker', {
          attrs: {
            x: 80 - w / 2,
            y: 52 - h / 2,
            r: 6,
            stroke: '#ff4d4f',
            cursor: 'pointer',
            symbol: COLLAPSE_ICON,
          },
          // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
          name: 'remove-item',
        })

        if (cfg.label) {
          group.addShape('text', {
            attrs: {
              ...labelCfg.style,
              text: cfg.label,
              x: 50 - w / 2,
              y: 25 - h / 2,
            },
          })
        }

        return keyShape
      },
      update: undefined,
    },
    'rect'
  )

  G6.registerEdge('flow-line', {
    draw(cfg, group) {
      const startPoint = cfg.startPoint
      const endPoint = cfg.endPoint

      const { style } = cfg
      const shape = group.addShape('path', {
        attrs: {
          stroke: style.stroke,
          endArrow: style.endArrow,
          path: [
            ['M', startPoint.x, startPoint.y],
            ['L', startPoint.x, (startPoint.y + endPoint.y) / 2],
            ['L', endPoint.x, (startPoint.y + endPoint.y) / 2],
            ['L', endPoint.x, endPoint.y],
          ],
        },
      })

      return shape
    },
  })

  const defaultStateStyles = {
    hover: {
      stroke: '#1890ff',
      lineWidth: 2,
    },
  }

  const defaultNodeStyle = {
    fill: '#91d5ff',
    stroke: '#40a9ff',
    radius: 5,
  }

  const defaultEdgeStyle = {
    stroke: '#91d5ff',
    endArrow: {
      path: 'M 0,0 L 12, 6 L 9,0 L 12, -6 Z',
      fill: '#91d5ff',
      d: -20,
    },
  }

  const defaultLayout = {
    type: 'compactBox',
    direction: 'TB',
    getId: function getId(d) {
      return d.id
    },
    getHeight: function getHeight() {
      return 16
    },
    getWidth: function getWidth() {
      return 16
    },
    getVGap: function getVGap() {
      return 40
    },
    getHGap: function getHGap() {
      return 70
    },
  }

  const defaultLabelCfg = {
    style: {
      fill: '#000',
      fontSize: 12,
    },
  }

  const container = document.getElementById('container')
  const width = container.scrollWidth
  const height = container.scrollHeight || 500

  const minimap = new G6.Minimap({
    size: [150, 100],
  })
  const graph = new G6.TreeGraph({
    container: 'container',
    width,
    height,
    linkCenter: true,
    plugins: [minimap],
    modes: {
      default: ['drag-canvas', 'zoom-canvas'],
    },
    defaultNode: {
      type: 'icon-node',
      size: [120, 40],
      style: defaultNodeStyle,
      labelCfg: defaultLabelCfg,
    },
    defaultEdge: {
      type: 'flow-line',
      style: defaultEdgeStyle,
    },
    nodeStateStyles: defaultStateStyles,
    edgeStateStyles: defaultStateStyles,
    layout: defaultLayout,
  })

  graph.data(data.value)
  graph.render()
  graph.fitView()

  graphInstance.value = graph

  graph.on('node:mouseenter', (evt) => {
    const { item } = evt
    graph.setItemState(item, 'hover', true)
  })

  graph.on('node:mouseleave', (evt) => {
    const { item } = evt
    graph.setItemState(item, 'hover', false)
  })

  graph.on('node:click', (evt) => {
    const { item, target } = evt
    const targetType = target.get('type')
    const name = target.get('name')
    console.log('containerRef.value type:', typeof containerRef.value)

    // console.log(containerRef.value.getNodes(), 'dsaf1')

    console.log(name, targetType)

    console.log(item, 'item')
    console.log(target, 'target')
    curNodeData.value = item?.getModel()
    console.log(curNodeData.value, 'curNodeData')

    if (curNodeData.value.nodeType !== 'publisher') {
      drawerVisible.value = true
    }
    // 增加元素
    if (targetType === 'marker') {
      const model = item.getModel()
      if (name === 'add-item') {
        if (!model.children) {
          model.children = []
        }
        let newNodeType = 'approver' // 默认为审批人
        if (model.nodeType === 'publisher') {
          newNodeType = 'condition' // 发起人下级为条件节点
        } else if (model.nodeType === 'condition') {
          newNodeType = 'approver' // 条件节点下级为审批人
        }

        const isRoot = model.nodeType === 'publisher'
        if (!isRoot && model.children.length >= 1) {
          // console.warn('该节点只允许有一个子节点')
          // return
          // 实现节点插入逻辑：新节点替代当前位置，原节点成为新节点的子节点
          // const existingChild = model.children[0]
          // 深拷贝现有的子节点，避免ID重复问题
          const existingChild = JSON.parse(JSON.stringify(model.children[0]))
          // 递归更新所有子节点的ID，确保唯一性
          const updateIds = (node) => {
            node.id = `n-${Math.random()}`
            if (node.children && node.children.length > 0) {
              node.children.forEach(updateIds)
            }
          }
          updateIds(existingChild)
          const id = `n-${Math.random()}`
          const newNode = {
            id,
            label: newNodeType === 'condition' ? `条件节点${model.children.length + 1}` : '审批人',
            nodeType: newNodeType,
            leftIcon: {
              style: {
                fill: '#e6fffb',
                stroke: '#e6fffb',
              },
              img: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Q_FQT6nwEC8AAAAAAAAAAABkARQnAQ',
            },
            children: [existingChild], // 原子节点成为新节点的子节点
          }

          // 替换原来的子节点
          model.children = [newNode]
          graph.updateChild(model, model.id, {
            animate: false,
          })
          return
        }

        const id = `n-${Math.random()}`
        // model.children.push({
        //   id,
        //   label: id.substr(0, 8),
        //   leftIcon: {
        //     style: {
        //       fill: '#e6fffb',
        //       stroke: '#e6fffb',
        //     },
        //     img: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Q_FQT6nwEC8AAAAAAAAAAABkARQnAQ',
        //   },
        // })
        const newNode = {
          id,
          label: newNodeType === 'condition' ? `条件节点${model.children.length + 1}` : '审批人',
          nodeType: newNodeType,
          leftIcon: {
            style: {
              fill: '#e6fffb',
              stroke: '#e6fffb',
            },
            img: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Q_FQT6nwEC8AAAAAAAAAAABkARQnAQ',
          },
        }
        model.children.push(newNode)
        graph.updateChild(model, model.id)
      } else if (name === 'remove-item') {
        graph.removeChild(model.id)
      }
    }
  })
  if (typeof window !== 'undefined')
    window.onresize = () => {
      if (!graph || graph.get('destroyed')) return
      if (!container || !container.scrollWidth || !container.scrollHeight) return
      graph.changeSize(container.scrollWidth, container.scrollHeight)
    }
}

onMounted(() => {
  initcontainerRef()
})

const drawerVisible = ref(false)

const handleClose = () => {
  drawerVisible.value = false
}

const approverConfig = ref({
  setType: '1',
})

const changeType = () => {}

const approvalUserId = ref(0)
const userOptions = ref([
  { value: 0, label: '张三' },
  { value: 1, label: '李四' },
  { value: 2, label: 'wanlao' },
])
const confirmClick = () => {
  drawerVisible.value = false
  const selectedUser = userOptions.value.find((item) => item.value === approvalUserId.value)
  // 把树图数据中 data 对应节点的label值 替换成 selectedUser.name
  console.log(graphInstance.value.getNodes(), 'graphInstance.value.getNodes()')
  curNodeData.value.label = selectedUser.label
  // 使用 graph 实例更新节点视图
  const node = graphInstance.value.findById(curNodeData.value.id)
  if (node) {
    graphInstance.value.updateItem(node, {
      label: selectedUser.label,
    })
  }
}
</script>

<template>
  <div>
    <div class="flow-graph-wrapper">
      <div ref="containerRef" id="container" class="flow-graph"></div>
      <el-drawer v-model="drawerVisible" title="I am the title" :with-header="false" @closed="handleClose">
        <div style="color: #000">
          <div v-if="curNodeData?.nodeType === 'condition'">条件设置区域</div>
          <div v-else>
            <el-card style="max-width: 480px">
              <template #header>
                <div class="card-header">
                  <span>💁设置审批人</span>
                </div>
              </template>
              <!-- <p v-for="o in 4" :key="o" class="text item">{{ 'List item ' + o }}</p> -->
              <!-- <template #footer>Footer content</template> -->
              <el-radio-group v-model="approverConfig.setType" class="clear" @change="changeType">
                <el-radio value="1">指定成员</el-radio>
                <el-radio value="2">直属上级</el-radio>
              </el-radio-group>
              <el-select-v2
                v-model="approvalUserId"
                :options="userOptions"
                placeholder="Please select"
                style="width: 240px" />
            </el-card>
          </div>
        </div>
        <template #footer>
          <div style="flex: auto">
            <el-button @click="handleClose">cancel</el-button>
            <el-button type="primary" @click="confirmClick">confirm</el-button>
          </div>
        </template>
      </el-drawer>
    </div>
    <el-button type="primary" @click="console.log(graphInstance.getNodes())">点击</el-button>
  </div>
</template>

<style scoped lang="scss">
.flow-graph-wrapper {
  background-color: #f8f8f8;
  margin-top: 20px;
  width: 100%;
  height: calc(100vh - 205px);
  overflow: auto;

  .flow-graph {
    width: 100%;
    height: inherit;
    // width: 1200px;
    // height: 1000px;
    // overflow: scroll;
    border-radius: 10px;
    background: -webkit-linear-gradient(top, transparent 20px, #eee 21px),
      -webkit-linear-gradient(left, transparent 20px, #eee 21px);
    background-size: 21px 21px;
  }
}
</style>
